﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Security;
using System.Security.Cryptography;
using System.Text;

using Common.Model;
using Common.Error;
using OpenAPI.IDAL;
using OpenAPI.IDAL.OAuth;
using OpenAPI.Model.OAuth;
using OpenAPI.BLL.OAuth;

namespace OpenAPI.Web.Mvc.Helper
{
    public abstract class APIHelper
    {
        private static string API_URL = System.Configuration.ConfigurationManager.AppSettings["API_URL"].ToString();//"http://localhost/api/rest";

        /// <summary>
        /// 产生令牌
        /// </summary>
        /// <returns></returns>
        public static string CreateOAuthToken()
        {
            return Utility.StringHelper.GetMd5String(Utility.StringHelper.GetGuidString());
        }

        /// <summary>
        /// 产生令牌密钥
        /// </summary>
        /// <returns></returns>
        public static string CreateOAuthTokenSecret()
        {
            return Utility.StringHelper.GetMd5String(Utility.StringHelper.GetGuidString());
        }

        /// <summary>
        /// 获取某方法的参数(需签名部分)
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static ArrayList GetSignArguments(string method)
        {
            ArrayList arguments = new ArrayList();

            foreach (OpenAPI.Model.API.MethodSignArgumentInfo argument in OpenAPI.BLL.API.MethodManager.GetSignArguments(method))
            {
                switch (argument.MethodSignArgumentPK.ARGUMENT_NAME.ToLower())
                {
                    case "oauth_timestamp":
                        arguments.Add(new ArgumentInfo(argument.MethodSignArgumentPK.ARGUMENT_NAME.ToLower(), GetTimeStemp().ToString()));
                        break;
                    case "oauth_nonce":
                        arguments.Add(new ArgumentInfo(argument.MethodSignArgumentPK.ARGUMENT_NAME.ToLower(), Utility.StringHelper.GetGuidString()));
                        break;
                    case "oauth_version":
                        arguments.Add(new ArgumentInfo(argument.MethodSignArgumentPK.ARGUMENT_NAME.ToLower(), "1.0"));
                        break;
                    default:
                        arguments.Add(new ArgumentInfo(argument.MethodSignArgumentPK.ARGUMENT_NAME.ToLower(), argument.ARGUMENT_VALUE));
                        break;
                }
            }

            return arguments;
        }


        /// <summary>
        /// 获取某方法的参数(不需签名部分)
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static ArrayList GetUnSignArguments(string method)
        {
            ArrayList arguments = new ArrayList();

            foreach (OpenAPI.Model.API.MethodUnSignArgumentInfo argument in OpenAPI.BLL.API.MethodManager.GetUnSignArguments(method))
            {
                arguments.Add(new ArgumentInfo(argument.MethodUnSignArgumentPK.ARGUMENT_NAME.ToLower(), argument.ARGUMENT_VALUE));
            }

            return arguments;
        }

        /// <summary>
        /// 获取密钥
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static string GetSignSecret(string method, out ErrorType error)
        {
            error = null;
            string secret = "";
            string secret_key = GetSignSecretKey(method);

            if (secret_key == "oauth_consumer_key")
            {
                secret = OpenAPI.BLL.OAuth.ConsumerManager.GetOAuthConsumerSecret(HttpContext.Current.Request["oauth_consumer_key"].ToString(), out error);
            }
            else if (secret_key == "oauth_token")
            {
                secret = OpenAPI.BLL.OAuth.ConsumerManager.GetOAuthTokenSecret(HttpContext.Current.Request["oauth_consumer_key"].ToString(), HttpContext.Current.Request["oauth_token"].ToString(), out error);
            }
            else
            {
                secret = "";
            }

            return secret;
        }

        /// <summary>
        /// 获取密钥的名称
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static string GetSignSecretKey(string method)
        {
            string secret_key = "";

            if (method.ToLower().Trim() == "openapi.oauth.requesttoken")
            {
                secret_key = "oauth_consumer_key";
            }
            else
            {
                secret_key = "oauth_token";
            }

            return secret_key;
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="api_method">API方法</param>
        /// <param name="api_signature">消费方提交的签名</param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool ValidateSignature(string api_method, string api_signature, out ErrorType error)
        {
            error = null;

            //获取签名密钥
            string secret = GetSignSecret(api_method, out error);

            //获取密钥出错
            if (string.IsNullOrEmpty(secret))
            {
                return false;
            }

            //获取签名参数表
            ArrayList arguments = GetRequestSignArguments(api_method);

            StringBuilder sb = new StringBuilder();

            //获取消费方参数及参数值
            ArrayList temp_arguments = new ArrayList();
            for (int i = 0; i < arguments.Count; i++)
            {
                ArgumentInfo argument = (ArgumentInfo)arguments[i];
                try
                {
                    temp_arguments.Add(new ArgumentInfo(argument.Name, argument.Value));
                }
                catch
                {
                    error = ErrorHelper.NewError("", "need argument:" + argument.Name);
                    return false;
                }
            }

            //对参数进行排序
            temp_arguments.Sort();

            //加入密钥
            sb.Append(secret);

            //合成签名
            for (int i = 0; i < temp_arguments.Count; i++)
            {
                ArgumentInfo argument = (ArgumentInfo)temp_arguments[i];

                sb.Append(argument.Name);
                sb.Append(HttpUtility.UrlEncode(argument.Value).ToLower());
            }

            //将字符串用MD5加密码，生成32位的签名
            string sig = Utility.StringHelper.GetMd5String(sb.ToString());

            //比较签名，返回比较结果
            bool flag = (api_signature == sig);
            if (flag)
            {
                error = null;
            }
            else
            {
                error = ErrorHelper.INVALID_SIGNATURE;
            }

            return flag;
        }


        /// <summary>
        /// 返回所有支持的API方法
        /// </summary>
        /// <param name="insertText"></param>
        /// <param name="insertValue"></param>
        /// <returns></returns>
        public static IList<SelectListItem> GetMethods(string insertText, string insertValue)
        {
            IList<SelectListItem> arguments = new List<SelectListItem>();

            arguments = GetMethods();

            //插入空值
            SelectListItem item_insert = new SelectListItem();
            item_insert.Text = insertText;
            item_insert.Value = insertValue;

            arguments.Insert(0, item_insert);

            return arguments;
        }


        /// <summary>
        /// 返回所有支持的API方法
        /// </summary>
        /// <returns></returns>
        public static IList<SelectListItem> GetMethods()
        {
            IList<SelectListItem> arguments = new List<SelectListItem>();

            foreach (OpenAPI.Model.API.MethodInfo method in OpenAPI.BLL.API.MethodManager.GetMethods("Y"))
            {
                SelectListItem item = new SelectListItem();
                item.Text = method.METHOD_NAME;
                item.Value = method.METHOD_NAME.ToLower();

                arguments.Add(item);
            }

            return arguments;
        }


        public static long GetTimeStemp()
        {
            TimeSpan ts = DateTime.Now - Convert.ToDateTime("1970-01-01");
            return (long)ts.TotalSeconds;
        }

        /// <summary>
        /// 拼参数URL
        /// </summary>
        /// <param name="method"></param>
        /// <param name="unSignArguments">不需签名参数列表</param>
        /// <param name="arguments">签名参数列表</param>
        /// <param name="secret"></param>
        /// <returns></returns>
        public static string GetUrl(string method, ArrayList unSignArguments, ArrayList arguments, string secret)
        {
            StringBuilder url = new StringBuilder();
            StringBuilder unsign_arguments_url = new StringBuilder();
            StringBuilder sign_arguments_url = new StringBuilder();
            StringBuilder sign = new StringBuilder();

            // 合成Url的前半部分
            url.AppendFormat("{0}?api_method={1}", API_URL, method);


            //合成不需签名参数
            for (int i = 0; i < unSignArguments.Count; i++)
            {
                ArgumentInfo argument = (ArgumentInfo)unSignArguments[i];

                // 合成
                unsign_arguments_url.Append("&");
                unsign_arguments_url.Append(argument.Name);
                unsign_arguments_url.Append("=");
                unsign_arguments_url.Append(HttpUtility.UrlEncode(argument.Value)); //对参数值进行UrlEncode编码
            }


            //排序需签名参数
            arguments.Sort();

            //加入密钥
            sign.Append(secret);
            //合成需签名参数
            for (int i = 0; i < arguments.Count; i++)
            {
                ArgumentInfo argument = (ArgumentInfo)arguments[i];

                // 合成
                sign_arguments_url.Append("&");
                sign_arguments_url.Append(argument.Name);
                sign_arguments_url.Append("=");
                sign_arguments_url.Append(HttpUtility.UrlEncode(argument.Value));   //对参数值进行UrlEncode编码

                //合成签名
                sign.Append(argument.Name);
                sign.Append(HttpUtility.UrlEncode(argument.Value).ToLower()); //对参数值进行UrlEncode编码
            }

            // 将字符串用MD5加密码，生成32位的签名
            string api_signature = Utility.StringHelper.GetMd5String(sign.ToString());

            // 合成整个URL
            url.Append(unsign_arguments_url);
            url.Append(sign_arguments_url);
            url.Append("&api_signature=");
            url.Append(api_signature);

            return url.ToString();
        }

        /// <summary>
        /// 获取签名
        /// </summary>
        /// <param name="method"></param>
        /// <param name="arguments"></param>
        /// <param name="secret"></param>
        /// <returns></returns>
        public static string GetSignature(string method, ArrayList arguments, string secret)
        {
            StringBuilder sign = new StringBuilder();

            //排序需签名参数
            arguments.Sort();

            //加入密钥
            sign.Append(secret);
            //合成需签名参数
            for (int i = 0; i < arguments.Count; i++)
            {
                ArgumentInfo argument = (ArgumentInfo)arguments[i];

                //合成签名
                sign.Append(argument.Name);
                sign.Append(HttpUtility.UrlEncode(argument.Value).ToLower()); //对参数值进行UrlEncode编码
            }

            // 将字符串用MD5加密码，生成32位的签名
            string api_signature = Utility.StringHelper.GetMd5String(sign.ToString());

            return api_signature;
        }


        #region 执行API方法

        /// <summary>
        /// 执行API方法
        /// </summary>
        /// <param name="method"></param>
        /// <returns>XML</returns>
        public static string ExecuteAPIMethod(string method)
        {
            IAPIProxy dal = CreateAPIProxy();
            string xml = "";
            ArrayList unSignArguments = GetRequestUnSignArguments(method);
            ArrayList signArguments = GetRequestSignArguments(method);

            xml = dal.ExecuteAPIMethod(method, unSignArguments, signArguments);

            return xml;
        }

        /// <summary>
        /// 获取Get/Post非签名参数
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static ArrayList GetRequestUnSignArguments(string method)
        {
            ArrayList unSignArguments = APIHelper.GetUnSignArguments(method);

            foreach (ArgumentInfo argument in unSignArguments)
            {
                argument.Value = Utility.StringHelper.GetRequest(argument.Name);
            }

            return unSignArguments;
        }

        /// <summary>
        /// 获取Get/Post签名参数
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static ArrayList GetRequestSignArguments(string method)
        {
            ArrayList arguments = APIHelper.GetSignArguments(method);

            foreach (ArgumentInfo argument in arguments)
            {
                argument.Value = Utility.StringHelper.GetRequest(argument.Name);
            }

            return arguments;
        }


        /// <summary>
        /// 创建IAPIProxy对象实例
        /// </summary>
        /// <returns></returns>
        private static IAPIProxy CreateAPIProxy()
        {
            string path = "";

            return (IAPIProxy)Utility.ReflectServiceLocator.LocateObject("ProxyBLL", path + "APIProxyManager");
        }

        #endregion

    }//
}
